#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h> // 主要的socket函数和数据结构
#include <netinet/in.h> // IPv4和IPv6地址结构
#include <arpa/inet.h>  // 地址转换函数
#include <unistd.h>
#include <cstring>
#include "Protocol.hpp"
using namespace std;

#define NUM 1024

class TcpClient
{
public:
    TcpClient(const string &ip, const uint16_t &port)
        : _sock(-1), _serverip(ip), _serverport(port)
    {
    }
    void initClient()
    {
        // 1.创建sock
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            cerr << "socket create error" << endl;
            exit(2);
        }
        // 2. tcp的客户端要不要bind?要的!要不要显示的bind?不要显示的bind
        // 3. 要不要listen?不要!
        // 4. 要不要accept?不要!
        // 5. 要什么？要发起连接
    }
    void start()
    {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        server.sin_port = htons(_serverport);

        if (connect(_sock, (struct sockaddr *)&server, sizeof(server)) != 0)
        {
            cerr << "socket connect error" << endl;
        }
        else
        {
            // 发送
            std::string line;
            std::string inbuffer;
            while (true)
            {
                std::cout << "mycal>> ";
                std::getline(std::cin, line); // 1+1
                // 先把数据结构化(不是网络的内容)

                Request req = ParseLine(line);
                std::string content;
                req.serialize(&content);                     // 序列化
                std::string send_string = enLength(content); // 添加报头
                send(_sock, send_string.c_str(), send_string.size() , 0);

                std::string Package, text;
                // 对于接收的数据要先保证获取的是一个完整的报文
                if (!recvPackage(_sock, inbuffer, &Package))
                    continue; //--得到一个完整的报文
                if (!deLength(Package, &text))
                    continue; //--处理报头，得到有效信息

                Response resp;
                resp.deserialize(text);
                std::cout << "exitCode: " << resp.exitcode << endl;
                std::cout << "result: " << resp.result << endl;
            }
        }
    }
    Request ParseLine(const std::string &line)//数据结构化
    {
        //"1+1"
        int statuc = 0; // 0:操作符之前，1：碰到了操作符，2：操作符之后
        int i = 0;
        std::string left, right;
        char op;
        while (i < line.size())
        {
            switch (statuc)
            {
            case 0:
                if (!isdigit(line[i])) // 如果不是数字
                {
                    op = line[i];
                    statuc = 1;
                }
                else
                {
                    left.push_back(line[i++]);
                }
                break;
            case 1:
                i++;
                statuc = 2;
                break;
            case 2:
                right.push_back(line[i++]);
                break;
            }
        }
        std::cout << std::stoi(left) <<" "<< std::stoi(right) << " " << op << std::endl;
        return Request(std::stoi(left), std::stoi(right), op);
    }

    ~TcpClient()
    {
        if (_sock >= 0)
        {
            close(_sock);
        }
    }

private:
    int _sock;
    uint16_t _serverport;
    string _serverip;
};